//
//	File: OyDirect3D9_SkinManager.h
//
#ifndef OYDIRECT3D9_SKINMANAGER_H
#define OYDIRECT3D9_SKINMANAGER_H


#include "../OyRenderer/OyRenderDevice.h"
#include "DataStruct/OyDataStruct.h"
#include <d3d9.h>
#include <tchar.h>


// The UnicodeString is a helper class wapper for TCHAR*
// usually save Relative file path, so 256 is enough
class UnicodeString
{
public:
	static const int MAX_FILENAME = 256;
	TCHAR m_string[MAX_FILENAME];

	// empty constructor
	UnicodeString() 
	{
		memset(m_string, 0, sizeof(TCHAR)*MAX_FILENAME);    
	}

	// copy-string constructor
	UnicodeString( const TCHAR* p_string )
	{
		_tcscpy_s( m_string, _countof(m_string), p_string );
	}

	// == operator
	bool operator == ( UnicodeString& p_right )
	{
		return !_tcscmp( m_string, p_right.m_string);
	}
};

class OyD3D9SkinManager : public OySkinManager
{
public:
	static const int MAX_TEXTURE_FILENAME_HASHTABLE_NUM = 4096;
	static const int INIT_MATERIAL_ARRAY_NUM = 512;
	static const int INIT_TEXTURE_ARRAY_NUM = 512;
	static const int INIT_SKIN_ARRAY_NUM = 512;

	static const int INIT_SYNC_TEXTURE_RESOURCE = 1024;


	OyD3D9SkinManager(LPDIRECT3DDEVICE9 pDevice);
    ~OyD3D9SkinManager(void);

	void	DeferedSyncResource();

	void    Reset(void);

	HRESULT AddSkin(const OyColor *pcAmbient,
					const OyColor *pcDiffuse,
					const OyColor *pcEmissive,
					const OyColor *pcSpecular,
					float fSpecPower, UINT *nSkinID);
	void	SetAlphaToSkin(UINT nSkinID, bool bAlpha);
	void	SetAlphaTestToSkin(UINT nSkinID, bool bAlphaTest);
	void	SetPrimitiveTypeToSkin(UINT nSkinID, char PrimitiveType);

	HRESULT AddTexture(UINT nSkinID, const TCHAR *chName, UINT slot = 0);
	HRESULT	AddDeferedTexture(UINT nSkinID, const TCHAR *chName, UINT slot = 0);
	HRESULT AddTextureHeightmapAsBump(UINT nSkinID, const TCHAR *chName, UINT slot = 0);


	bool	GetTextureInfo(const TCHAR *chName, UINT& width, UINT& height, UINT& bits);

	bool	LoadTextureData(const TCHAR *chName, void *rawData);

	//HRESULT ExchangeTexture(UINT nSkinID, UINT nTexStage, const TCHAR *chName);

	//HRESULT ExchangeMaterial(UINT nSkinID,
	//						const OyColor *pcAmbient,
	//						const OyColor *pcDiffuse,
	//						const OyColor *pcEmissive,
	//						const OyColor *pcSpecular,
	//						float fSpecPower);

	inline bool MaterialEqual(const OyMaterial *pMat0, const OyMaterial *pMat1)
	{
		if ( !ColorEqual(&pMat0->cAmbient,  &pMat1->cAmbient)  || 
			 !ColorEqual(&pMat0->cDiffuse,  &pMat1->cDiffuse)  || 
			 !ColorEqual(&pMat0->cEmissive, &pMat1->cEmissive) ||
			 !ColorEqual(&pMat0->cSpecular, &pMat1->cSpecular) || 
			 (pMat0->fPower != pMat1->fPower) )
			return false;
		return true;
	}

	inline bool ColorEqual(const OyColor *pCol0, const OyColor *pCol1)
	{
		if( (pCol0->fA != pCol1->fA) || (pCol0->fR != pCol1->fR) ||     
			(pCol0->fG != pCol1->fG) || (pCol0->fB != pCol1->fB) )
			return false;
		return true;
	}

	//void LogCurrentStatus(char *chLog, bool bDetailed);
      
	inline UINT GetNumSkins(void) { return m_nNumSkins; }

	OySkin GetSkin(UINT nSkinID);

	OyMaterial GetMaterial(UINT nMatID);

	const TCHAR* GetTextureName(UINT TexID);
	const void* GetOyTextureData(UINT TexID);

private:
	HRESULT CreateTexture(OyTexture *pTexture);
	HRESULT ConvertToNormalmap(OyTexture *pTexture);

private:
	TCHAR				m_ErrorString[256];	   // Log Error String

	UINT				m_nNumSkins;           // number (IDs) of skins
	UINT				m_nNumMaterials;       // number (IDs) of materials
	UINT				m_nNumTextures;        // number (IDs) of textures
	OyArray<OySkin>     m_Skins;               // allocate mem for skins here
	OyArray<OyMaterial> m_Materials;           // allocate mem for materials here
	OyArray<OyTexture>  m_Textures;            // allocate mem for textures here

	HashTable<UnicodeString, unsigned int> m_TexNameIDMap; // Map of Texture string name => UINT ID

	LPDIRECT3DDEVICE9	m_pDevice;			   // D3D device

private:
	struct DLTexture
	{
		static const int MAX_TEXFILENAME = 256;
		UINT m_skinID;
		TCHAR m_filename[MAX_TEXFILENAME];
		UINT m_slot;
	};

	DoubleLinkedList< RingFIFO<DLTexture>* > m_SyncLoadTextureList;
};

#endif